home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CU Amiga Super CD-ROM 14
/
CU Amiga Magazine's Super CD-ROM 14 (1997)(EMAP Images)(GB)(Track 1 of 3)[!][issue 1997-09].iso
/
CUCD
/
Programming
/
RKMLibsPrgs
/
intuition
/
menus
/
menulayout.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-09-03
|
22KB
|
581 lines
;/* menulayout.c - Execute me to compile me with SAS C 5.10
LC -b1 -cfistq -v -y -j73 menulayout.c
Blink FROM LIB:c.o,menulayout.o TO menulayout LIBRARY LIB:LC.lib,LIB:Amiga.lib
quit
*/
/*
Copyright (c) 1992 Commodore-Amiga, Inc.
This example is provided in electronic form by Commodore-Amiga, Inc. for
use with the "Amiga ROM Kernel Reference Manual: Libraries", 3rd Edition,
published by Addison-Wesley (ISBN 0-201-56774-1).
The "Amiga ROM Kernel Reference Manual: Libraries" contains additional
information on the correct usage of the techniques and operating system
functions presented in these examples. The source and executable code
of these examples may only be distributed in free electronic form, via
bulletin board or as part of a fully non-commercial and freely
redistributable diskette. Both the source and executable code (including
comments) must be included, without modification, in any copy. This
example may not be published in printed form or distributed with any
commercial product. However, the programming techniques and support
routines set forth in these examples may be used in the development
of original executable software products for Commodore Amiga computers.
All other rights reserved.
This example is provided "as-is" and is subject to change; no
warranties are made. All use is at your own risk. No liability or
responsibility is assumed.
*/
/*
** menulayout.c - Example showing how to do menu layout in general. This example
** also illustrates handling menu events, including IDCMP_MENUHELP events.
**
** Note that handling arbitrary fonts is fairly complex. Applications that require V37
** should use the simpler menu layout routines found in the GadTools library.
*/
#define INTUI_V36_NAMES_ONLY
#include <exec/types.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <graphics/gfxbase.h>
#include <dos/dos.h>
#include <clib/exec_protos.h>
#include <clib/graphics_protos.h>
#include <clib/intuition_protos.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifdef LATTICE
int CXBRK(void) { return(0); } /* Disable Lattice CTRL/C handling */
int chkabort(void) { return(0); } /* really */
#endif
/* Our function prototypes */
BOOL processMenus(USHORT selection, BOOL done);
BOOL handleIDCMP(struct Window *win);
USHORT MaxLength(struct RastPort *textRPort, struct MenuItem *first_item, USHORT char_size);
VOID setITextAttr(struct IntuiText *first_IText, struct TextAttr *textAttr);
VOID adjustItems(struct RastPort *textRPort, struct MenuItem *first_item, struct TextAttr *textAttr,
USHORT char_size, USHORT height, USHORT level, USHORT left_edge);
BOOL adjustMenus(struct Menu *first_menu, struct TextAttr *textAttr);
LONG doWindow(void);
/* Settings Item IntuiText */
struct IntuiText SettText[] = {
{0,1,JAM2,2, 1, NULL, "Sound...", NULL },
{0,1,JAM2,CHECKWIDTH,1, NULL, " Auto Save", NULL },
{0,1,JAM2,CHECKWIDTH,1, NULL, " Have Your Cake", NULL },
{0,1,JAM2,CHECKWIDTH,1, NULL, " Eat It Too", NULL }
};
struct MenuItem SettItem[] = {
{ /* "Sound..." */
&SettItem[1], 0, 0, 0, 0, ITEMTEXT|ITEMENABLED|HIGHCOMP, 0,
(APTR)&SettText[0], NULL, NULL, NULL, MENUNULL },
{ /* "Auto Save" (toggle-select, initially selected) */
&SettItem[2], 0, 0, 0, 0, ITEMTEXT|ITEMENABLED|HIGHCOMP|CHECKIT|MENUTOGGLE|CHECKED, 0,
(APTR)&SettText[1], NULL, NULL, NULL, MENUNULL },
{ /* "Have Your Cake" (initially selected, excludes "Eat It Too") */
&SettItem[3], 0, 0, 0, 0, ITEMTEXT|ITEMENABLED|HIGHCOMP|CHECKIT|CHECKED, 8,
(APTR)&SettText[2], NULL, NULL, NULL, MENUNULL },
{ /* "Eat It Too" (excludes "Have Your Cake") */
NULL, 0, 0, 0, 0, ITEMTEXT|ITEMENABLED|HIGHCOMP|CHECKIT, 4,
(APTR)&SettText[3], NULL, NULL, NULL, MENUNULL }
};
/* Edit Menu Item IntuiText */
struct IntuiText EditText[] = {
{0,1,JAM2,2,1, NULL, "Cut", NULL },
{0,1,JAM2,2,1, NULL, "Copy", NULL },
{0,1,JAM2,2,1, NULL, "Paste", NULL },
{0,1,JAM2,2,1, NULL, "Erase", NULL },
{0,1,JAM2,2,1, NULL, "Undo", NULL }
};
/* Edit Menu Items */
struct MenuItem EditItem[] = {
{ /* "Cut" (key-equivalent: 'X') */
&EditItem[1], 0, 0, 0, 0, ITEMTEXT|COMMSEQ|ITEMENABLED|HIGHCOMP, 0,
(APTR)&EditText[0], NULL, 'X', NULL, MENUNULL },
{ /* "Copy" (key-equivalent: 'C') */
&EditItem[2], 0, 0, 0, 0, ITEMTEXT|COMMSEQ|ITEMENABLED|HIGHCOMP, 0,
(APTR)&EditText[1], NULL, 'C', NULL, MENUNULL },
{ /* "Paste" (key-equivalent: 'V') */
&EditItem[3], 0, 0, 0, 0, ITEMTEXT|COMMSEQ|ITEMENABLED|HIGHCOMP, 0,
(APTR)&EditText[2], NULL, 'V', NULL, MENUNULL },
{ /* "Erase" (disabled) */
&EditItem[4], 0, 0, 0, 0, ITEMTEXT|HIGHCOMP, 0,
(APTR)&EditText[3], NULL, NULL, NULL, MENUNULL },
{ /* "Undo" MenuItem (key-equivalent: 'Z') */
NULL, 0, 0, 0, 0, ITEMTEXT|COMMSEQ|ITEMENABLED|HIGHCOMP, 0,
(APTR)&EditText[4], NULL, 'Z', NULL, MENUNULL }
};
/* IntuiText for the Print Sub-Items */
struct IntuiText PrtText[] = {
{0,1, JAM2,2,1, NULL, "NLQ", NULL },
{0,1, JAM2,2,1, NULL, "Draft", NULL }
};
/* Print Sub-Items */
struct MenuItem PrtItem[] = {
{ /* "NLQ" */
&PrtItem[1], 0, 0, 0, 0, ITEMTEXT|ITEMENABLED|HIGHCOMP, 0,
(APTR)&PrtText[0], NULL, NULL, NULL, MENUNULL },
{ /* "Draft" */
NULL, 0, 0, 0, 0, ITEMTEXT|ITEMENABLED|HIGHCOMP, 0,
(APTR)&PrtText[1], NULL, NULL, NULL, MENUNULL }
};
/* Uses the >> character to indicate a sub-menu item.
** This is \273 Octal, 0xBB Hex or Alt-0 from the Keyboard.
**
** NOTE that standard menus place this character at the right margin of the menu box.
** This may be done by using a second IntuiText structure for the single character,
** linking this IntuiText to the first one, and positioning the IntuiText so that the
** character appears at the right margin. GadTools library will provide the correct behavior.
*/
/* Project Menu Item IntuiText */
struct IntuiText ProjText[] = {
{0,1, JAM2,2,1, NULL, "New", NULL },
{0,1, JAM2,2,1, NULL, "Open...", NULL },
{0,1, JAM2,2,1, NULL, "Save", NULL },
{0,1, JAM2,2,1, NULL, "Save As...", NULL },
{0,1, JAM2,2,1, NULL, "Print \273", NULL },
{0,1, JAM2,2,1, NULL, "About...", NULL },
{0,1, JAM2,2,1, NULL, "Quit", NULL }
};
/* Project Menu Items */
struct MenuItem ProjItem[] = {
{ /* "New" (key-equivalent: 'N' */
&ProjItem[1],0, 0, 0, 0, ITEMTEXT|COMMSEQ|ITEMENABLED|HIGHCOMP, 0,
(APTR)&ProjText[0], NULL, 'N', NULL, MENUNULL },
{ /* "Open..." (key-equivalent: 'O') */
&ProjItem[2],0, 0, 0, 0, ITEMTEXT|COMMSEQ|ITEMENABLED|HIGHCOMP, 0,
(APTR)&ProjText[1], NULL, 'O', NULL, MENUNULL },
{ /* "Save" (key-equivalent: 'S') */
&ProjItem[3],0, 0, 0, 0, ITEMTEXT|COMMSEQ|ITEMENABLED|HIGHCOMP, 0,
(APTR)&ProjText[2], NULL, 'S', NULL, MENUNULL },
{ /* "Save As..." (key-equivalent: 'A') */
&ProjItem[4],0, 0, 0, 0, ITEMTEXT|COMMSEQ|ITEMENABLED|HIGHCOMP, 0,
(APTR)&ProjText[3], NULL, 'A', NULL, MENUNULL },
{ /* "Print" (has sub-menu) */
&ProjItem[5],0, 0, 0, 0, ITEMTEXT|ITEMENABLED|HIGHCOMP, 0,
(APTR)&ProjText[4], NULL, NULL, &PrtItem[0], MENUNULL },
{ /* "About..." */
&ProjItem[6],0, 0, 0, 0, ITEMTEXT|ITEMENABLED|HIGHCOMP, 0,
(APTR)&ProjText[5], NULL, NULL, NULL, MENUNULL },
{ /* "Quit" (key-equivalent: 'Q' */
NULL, 0, 0, 0, 0, ITEMTEXT|COMMSEQ|ITEMENABLED|HIGHCOMP, 0,
(APTR)&ProjText[6], NULL, 'Q', NULL, MENUNULL }
};
/* Menu Titles */
struct Menu Menus[] = {
{&Menus[1], 0, 0, 63, 0, MENUENABLED, "Project", &ProjItem[0]},
{&Menus[2], 70, 0, 39, 0, MENUENABLED, "Edit", &EditItem[0]},
{NULL, 120, 0, 88, 0, MENUENABLED, "Settings", &SettItem[0]},
};
/* A pointer to the first menu for easy reference */
struct Menu *FirstMenu = &Menus[0];
/* Window Text for Explanation of Program */
struct IntuiText WinText[] = {
{0, 0, JAM2, 0, 0, NULL, "How to do a Menu", NULL},
{0, 0, JAM2, 0, 0, NULL, "(with Style)", &WinText[0]}
};
/* Globals */
struct Library *IntuitionBase = NULL;
struct Library *GfxBase = NULL;
/* open all of the required libraries. Note that we require
** Intuition V37, as the routine uses OpenWindowTags().
*/
VOID main(int argc, char **argv)
{
LONG returnValue;
/* This gets set to RETURN_OK if everything goes well. */
returnValue = RETURN_FAIL;
/* Open the Intuition Library */
IntuitionBase = OpenLibrary("intuition.library", 37);
if (IntuitionBase)
{
/* Open the Graphics Library */
GfxBase = (struct GfxBase *)OpenLibrary("graphics.library", 33);
if (GfxBase)
{
returnValue = doWindow();
CloseLibrary(GfxBase);
}
CloseLibrary(IntuitionBase);
}
exit(returnValue);
}
/* Open a window with some properly positioned text. Layout and set
** the menus, then process any events received. Cleanup when done.
*/
LONG doWindow()
{
struct Window *window;
struct Screen *screen;
struct DrawInfo *drawinfo;
ULONG signalmask, signals;
ULONG win_width, alt_width, win_height;
LONG returnValue = RETURN_FAIL;
BOOL done = FALSE;
if (screen = LockPubScreen(NULL))
{
if (drawinfo = GetScreenDrawInfo(screen))
{
/* get the colors for the window text */
WinText[0].FrontPen = WinText[1].FrontPen = drawinfo->dri_Pens[TEXTPEN];
WinText[0].BackPen = WinText[1].BackPen = drawinfo->dri_Pens[BACKGROUNDPEN];
/* use the screen's font for the text */
WinText[0].ITextFont = WinText[1].ITextFont = screen->Font;
/* calculate window size */
win_width = 100 + IntuiTextLength(&(WinText[0]));
alt_width = 100 + IntuiTextLength(&(WinText[1]));
if (win_width < alt_width)
win_width = alt_width;
win_height = 1 + screen->WBorTop + screen->WBorBottom +
(screen->Font->ta_YSize * 5);
/* calculate the correct positions for the text in the window */
WinText[0].LeftEdge = (win_width - IntuiTextLength(&(WinText[0]))) >> 1;
WinText[0].TopEdge = 1 + screen->WBorTop + (2 * screen->Font->ta_YSize);
WinText[1].LeftEdge = (win_width - IntuiTextLength(&(WinText[1]))) >> 1;
WinText[1].TopEdge = WinText[0].TopEdge + screen->Font->ta_YSize;
/* Open the window */
window = OpenWindowTags(NULL,
WA_PubScreen, screen,
WA_IDCMP, IDCMP_MENUPICK | IDCMP_CLOSEWINDOW | IDCMP_MENUHELP,
WA_Flags, WFLG_DRAGBAR | WFLG_DEPTHGADGET | WFLG_CLOSEGADGET |
WFLG_ACTIVATE | WFLG_NOCAREREFRESH,
WA_Left, 10, WA_Top, screen->BarHeight + 1,
WA_Width, win_width, WA_Height, win_height,
WA_Title, "Menu Example", WA_MenuHelp, TRUE,
TAG_END);
if (window)
{
returnValue = RETURN_OK; /* program initialized ok */
/* Give a brief explanation of the program */
PrintIText(window->RPort,&WinText[1],0,0);
/* Adjust the menu to conform to the font (TextAttr) */
adjustMenus(FirstMenu, window->WScreen->Font);
/* attach the menu to the window */
SetMenuStrip(window, FirstMenu);
/* Set up the signals that you want to hear about ... */
signalmask = 1L << window->UserPort->mp_SigBit;
/* And wait to hear from your signals */
while (!done)
{
signals = Wait(signalmask);
if (signals & signalmask) done = handleIDCMP(window);
};
/* clean up everything used here */
ClearMenuStrip(window);
CloseWindow(window);
}
FreeScreenDrawInfo(screen,drawinfo);
}
UnlockPubScreen(NULL,screen);
}
return(returnValue);
}
/* print out what menu was selected. Properly handle the IDCMP_MENUHELP
** events. Set done to TRUE if quit is selected.
*/
BOOL processMenus(USHORT selection, BOOL done)
{
USHORT flags;
USHORT menuNum, itemNum, subNum;
menuNum = MENUNUM(selection);
itemNum = ITEMNUM(selection);
subNum = SUBNUM(selection);
/* when processing IDCMP_MENUHELP, you are not guaranteed
** to get a menu item.
*/
if (itemNum != NOITEM)
{
flags = ((struct MenuItem *)ItemAddress(FirstMenu,(LONG)selection))->Flags;
if (flags & CHECKED)
printf("(Checked) ");
}
switch (menuNum)
{
case 0: /* Project Menu */
switch (itemNum)
{
case NOITEM: printf("Project Menu\n"); break;
case 0: printf("New\n"); break;
case 1: printf("Open\n"); break;
case 2: printf("Save\n"); break;
case 3: printf("Save As\n"); break;
case 4: printf("Print ");
switch (subNum)
{
case NOSUB: printf("Item\n"); break;
case 0: printf("NLQ\n"); break;
case 1: printf("Draft\n"); break;
}
break;
case 5: printf("About\n"); break;
case 6: printf("Quit\n"); done = TRUE; break;
}
break;
case 1: /* Edit Menu */
switch (itemNum) {
case NOITEM: printf("Edit Menu\n"); break;
case 0: printf("Cut\n"); break;
case 1: printf("Copy\n"); break;
case 2: printf("Paste\n"); break;
case 3: printf("Erase\n"); break;
case 4: printf("Undo\n"); break;
}
break;
case 2: /* Settings Menu */
switch (itemNum) {
case NOITEM: printf("Settings Menu\n"); break;
case 0: printf("Sound\n"); break;
case 1: printf("Auto Save\n"); break;
case 2: printf("Have Your Cake\n"); break;
case 3: printf("Eat It Too\n"); break;
}
break;
case NOMENU: /* No menu selected, can happen with IDCMP_MENUHELP */
printf("no menu\n");
break;
}
return(done);
}
/* Handle the IDCMP messages. Set done to TRUE if quit or closewindow is selected. */
BOOL handleIDCMP(struct Window *win)
{
BOOL done;
USHORT code, selection;
struct IntuiMessage *message = NULL;
ULONG class;
done = FALSE;
/* Examine pending messages */
while (message = (struct IntuiMessage *)GetMsg(win->UserPort)) {
class = message->Class;
code = message->Code;
/* When we're through with a message, reply */
ReplyMsg((struct Message *)message);
/* See what events occurred */
switch (class) {
case IDCMP_CLOSEWINDOW:
done = TRUE;
break;
case IDCMP_MENUHELP:
/*
** The routine that handles the menus for IDCMP_MENUHELP must be very careful
** it can receive menu information that is impossible under IDCMP_MENUPICK.
** For instance, the code value on a IDCMP_MENUHELP may have a valid number
** for the menu, then NOITEM and NOSUB. IDCMP_MENUPICK would get MENUNULL
** in this case. IDCMP_MENUHELP never come as multi-select items, and the
** event terminates the menu processing session.
**
** Note that I do not keep the return value from the processMenus() routine here--the
** application should not quit if the user selects "help" over the quit menu item.
*/
printf("IDCMP_MENUHELP: Help on ");
processMenus(code,done);
break;
case IDCMP_MENUPICK:
for ( selection = code; selection != MENUNULL;
selection = (ItemAddress(FirstMenu,(LONG)selection))->NextSelect)
{
printf("IDCMP_MENUPICK: Selected ");
done = processMenus(selection,done);
}
break;
}
}
return(done);
}
/* Steps thru each item to determine the maximum width of the strip */
USHORT MaxLength(struct RastPort *textRPort, struct MenuItem *first_item, USHORT char_size)
{
USHORT maxLength;
USHORT total_textlen;
struct MenuItem *cur_item;
struct IntuiText *itext;
USHORT extra_width;
USHORT maxCommCharWidth;
USHORT commCharWidth;
extra_width = char_size; /* used as padding for each item. */
/* Find the maximum length of a command character, if any.
** If found, it will be added to the extra_width field.
*/
maxCommCharWidth = 0;
for (cur_item = first_item; cur_item != NULL; cur_item = cur_item->NextItem)
{
if (cur_item->Flags & COMMSEQ)
{
commCharWidth = TextLength(textRPort,&(cur_item->Command),1);
if (commCharWidth > maxCommCharWidth)
maxCommCharWidth = commCharWidth;
}
}
/* if we found a command sequence, add it to the extra required space. Add
** space for the Amiga key glyph plus space for the command character. Note
** this only works for HIRES screens, for LORES, use LOWCOMMWIDTH.
*/
if (maxCommCharWidth > 0)
extra_width += maxCommCharWidth + COMMWIDTH;
/* Find the maximum length of the menu items, given the extra width calculated above. */
maxLength = 0;
for (cur_item = first_item; cur_item != NULL; cur_item = cur_item->NextItem)
{
itext = (struct IntuiText *)cur_item->ItemFill;
total_textlen = extra_width + itext->LeftEdge +
TextLength(textRPort, itext->IText, strlen(itext->IText));
/* returns the greater of the two */
if (total_textlen > maxLength)
maxLength = total_textlen;
}
return(maxLength);
}
/* Set all IntuiText in a chain (they are linked through the NextText ** field) to the same font. */
VOID setITextAttr(struct IntuiText *first_IText, struct TextAttr *textAttr)
{
struct IntuiText *cur_IText;
for (cur_IText = first_IText; cur_IText != NULL; cur_IText = cur_IText->NextText)
cur_IText->ITextFont = textAttr;
}
/* Adjust the MenuItems and SubItems */
VOID adjustItems(struct RastPort *textRPort, struct MenuItem *first_item,
struct TextAttr *textAttr, USHORT char_size, USHORT height,
USHORT level, USHORT left_edge)
{
register USHORT item_num;
struct MenuItem *cur_item;
USHORT strip_width, subitem_edge;
if (first_item == NULL)
return;
/* The width of this strip is the maximum length of its members. */
strip_width = MaxLength(textRPort, first_item, char_size);
/* Position the items. */
for (cur_item = first_item, item_num = 0; cur_item != NULL; cur_item = cur_item->NextItem, item_num++)
{
cur_item->TopEdge = (item_num * height) - level;
cur_item->LeftEdge = left_edge;
cur_item->Width = strip_width;
cur_item->Height = height;
/* place the sub_item 3/4 of the way over on the item. */
subitem_edge = strip_width - (strip_width >> 2);
setITextAttr((struct IntuiText *)cur_item->ItemFill, textAttr);
adjustItems(textRPort,cur_item->SubItem,textAttr,char_size,height,1,subitem_edge);
}
}
/* The following routines adjust an entire menu system to conform to the specified fonts' width and
** height. Allows for Proportional Fonts. This is necessary for a clean look regardless of what the
** users preference in Fonts may be. Using these routines, you don't need to specify TopEdge,
** LeftEdge, Width or Height in the MenuItem structures.
**
** NOTE that this routine does not work for menus with images, but assumes that all menu items are
** rendered with IntuiText.
**
** This set of routines does NOT check/correct if the menu runs off
** the screen due to large fonts, too many items, lo-res screen.
*/
BOOL adjustMenus(struct Menu *first_menu, struct TextAttr *textAttr)
{
struct RastPort textrp = {0}; /* Temporary RastPort */
struct Menu *cur_menu;
struct TextFont *font; /* Font to use */
USHORT start, char_size, height;
BOOL returnValue = FALSE;
/* open the font */
if (font = OpenFont(textAttr))
{
SetFont(&textrp, font); /* Put font into temporary RastPort */
char_size = TextLength(&textrp, "n", 1); /* Get the Width of the Font */
/* To prevent crowding of the Amiga key when using COMMSEQ, don't allow the items to be less
** than 8 pixels high. Also, add an extra pixel for inter-line spacing.
*/
if (font->tf_YSize > 8)
height = 1 + font->tf_YSize;
else
height = 1 + 8;
start = 2; /* Set Starting Pixel */
/* Step thru the menu structure and adjust it */
for (cur_menu = first_menu; cur_menu != NULL; cur_menu = cur_menu->NextMenu)
{
cur_menu->LeftEdge = start;
cur_menu->Width = char_size +
TextLength(&textrp, cur_menu->MenuName, strlen(cur_menu->MenuName));
adjustItems(&textrp, cur_menu->FirstItem, textAttr, char_size, height, 0, 0);
start += cur_menu->Width + char_size + char_size;
}
CloseFont(font); /* Close the Font */
returnValue = TRUE;
}
return(returnValue);
}